package utils.parser
{
	import flash.display3D.Context3D;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.VertexBuffer3D;
	import flash.geom.Vector3D;
	import flash.utils.ByteArray;
	
	import utils.base.Joint;
	import utils.base.Mesh;
	import utils.base.MeshVertex;
	import utils.base.Weight;
	import utils.math.Quaternion;

	public class Stage3D_md5mesh_parser
	{
		//顶点索引
		//顶点位置
		public var _rawPositionsBuffer:Vector.<Number>;
		//贴图位置
		private var _rawUvBuffer:Vector.<Number>;
		
		private var _jointsAry:Vector.<Joint>;
		
		private var _meshVeterAry:Vector.<MeshVertex>;
		private var _weightAry:Vector.<Weight>;
		private var _rawIndexBuffer:Vector.<uint>;
		
		public var meshAry:Vector.<Mesh>;
		private var _mesh:Mesh;
		
		// the final buffers in Molehill-ready format
		/*protected var _indexBuffer:IndexBuffer3D;
		protected var _positionsBuffer:VertexBuffer3D;
		protected var _uvBuffer:VertexBuffer3D;*/
		
		private const LINE_FEED:String = String.fromCharCode(10);
		private const SPACE:String = String.fromCharCode(32);
		private const JOINTS:String = "joints";
		private const MESH:String = "mesh";
		private const VERT:String = "vert";
		private const TRI:String = "tri";
		private const WEIGHT:String = "weight";
		
		private var flag:String; 
		private var _context3d:Context3D;
		public function Stage3D_md5mesh_parser(definition:String,context:Context3D)
		{
			_rawPositionsBuffer = new Vector.<Number>();
			_rawUvBuffer = new Vector.<Number>();
			_jointsAry = new Vector.<Joint>;
			
			_meshVeterAry = new Vector.<MeshVertex>;
			_weightAry = new Vector.<Weight>;
			_rawIndexBuffer = new Vector.<uint>();
			
			meshAry = new Vector.<Mesh>;
			_mesh = new Mesh(_meshVeterAry,_weightAry,_rawIndexBuffer);
			meshAry.push(_mesh);
			
			this._context3d = context;
			
			var lines:Array = definition.split(LINE_FEED);
			var loop:uint = lines.length;
			
			for(var i:uint = 0; i < loop; ++i){
				var t:String = lines[i];
				if(t.search(JOINTS + " {") == 0){
					flag = JOINTS;
				}else if(t.search(MESH + " {") == 0){
					if(flag == MESH){
						_meshVeterAry = new Vector.<MeshVertex>;
						_weightAry = new Vector.<Weight>;
						_rawIndexBuffer = new Vector.<uint>();
						
						_mesh = new Mesh(_meshVeterAry,_weightAry,_rawIndexBuffer);
						meshAry.push(_mesh);
						//break;
					}
					flag = MESH;
				}
				parseLine(t);
			}
			trace("meshAry.length:" + meshAry.length);
			processData();
			trace("com")
			
			printByte();
		}
		
		private var jointByte:ByteArray = new ByteArray;
		private var vertByte:ByteArray = new ByteArray;
		private var triByte:ByteArray = new ByteArray;
		private var weightByte:ByteArray = new ByteArray;
		
		private function printByte():void{
			jointByte.position = 0
			vertByte.position = 0;
			triByte.position = 0;
			weightByte.position = 0;
			var newByte:ByteArray = new ByteArray();
			newByte.writeBytes(jointByte,0,jointByte.length);
			newByte.writeBytes(vertByte,0,vertByte.length);
			newByte.writeBytes(triByte,0,triByte.length);
			newByte.writeBytes(weightByte,0,weightByte.length);
			newByte.compress();
			trace((jointByte.length+vertByte.length+triByte.length+weightByte.length),newByte.length);
			/*var file:File = File.desktopDirectory.resolvePath("123");
			var fs:FileStream = new FileStream;
			fs.open(file,FileMode.WRITE);
			fs.writeBytes(newByte,0,newByte.length);
			fs.close();*/
			/*while(jointByte.bytesAvailable){
				trace(jointByte.readInt(),jointByte.readDouble(),jointByte.readDouble(),jointByte.readDouble(),jointByte.readDouble(),jointByte.readDouble(),jointByte.readDouble());
			}
			trace("*************");
			while(vertByte.bytesAvailable){
				trace(vertByte.readDouble(),vertByte.readDouble(),vertByte.readInt(),vertByte.readInt());
			}
			trace("*************");
			while(triByte.bytesAvailable){
				trace(triByte.readInt(),triByte.readInt(),triByte.readInt());
			}
			trace("*************");
			while(weightByte.bytesAvailable){
				trace(weightByte.readInt(),weightByte.readDouble(),weightByte.readDouble(),weightByte.readDouble(),weightByte.readDouble());
			}*/
		}
		private function parseLine(line:String):void{
			if(flag == JOINTS){
				processJoints(line);
			}else if(flag == MESH){
				processMesh(line);
			}
		}
		
		private function processJoints(line:String):void{
			var r:RegExp = /"\t(.*?) .?/gi;
			var re:* = r.exec(line);
			var index:int;
			if(re){
				index = int(re[1]);
			}
			r = /\( (.*?) \).?/gi;
			re = r.exec(line);
			var ar:Array = new Array;
			while(re)
			{
				ar.push(re[1]);
				re = r.exec(line);
			}
			if(ar.length != 2){
				return;
			}
			var qua:Quaternion = new Quaternion();
			var v3d:Vector3D = getVecter3DByString(ar[1]);
			qua.x = v3d.x;
			qua.y = v3d.y;
			qua.z = v3d.z;
			qua.computeW();
			var joint:Joint = new Joint(index,getVecter3DByString(ar[0]),qua);
			_jointsAry.push(joint);
			joint.writeBytes(jointByte);
			
		}
		
		private function processMesh(line:String):void{
			line = line.replace("\t","");
			var ary:Array = line.split(SPACE);
			if(ary[0] == VERT){
				_meshVeterAry.push(new MeshVertex(converFloat(ary[3]),converFloat(ary[4]),ary[6],ary[7]));
				/*vertByte.writeFloat(Number(ary[3]));
				vertByte.writeFloat(Number(ary[4]));
				vertByte.writeInt(int(ary[6]));
				vertByte.writeInt(int(ary[7]));*/
			}else if(ary[0] == TRI){
				_rawIndexBuffer.push(ary[2],ary[3],ary[4]);
				/*triByte.writeInt(int(ary[2]));
				triByte.writeInt(int(ary[3]));
				triByte.writeInt(int(ary[4]));*/
			}else if(ary[0] == WEIGHT){
				_weightAry.push(new Weight(ary[2],converFloat(ary[3]),new Vector3D(converFloat(ary[5]),converFloat(ary[6]),converFloat(ary[7]))));
				/*weightByte.writeInt(int(ary[2]));
				weightByte.writeFloat(Number(ary[3]));
				weightByte.writeFloat(Number(ary[5]));
				weightByte.writeFloat(Number(ary[6]));
				weightByte.writeFloat(Number(ary[7]));*/
			}
		}
		
		private function getVecter3DByString(str:String):Vector3D{
			var ary:Array = str.split(SPACE);
			return new Vector3D(converFloat(ary[0]),converFloat(ary[1]),converFloat(ary[2]));
		}
		
		private function processData():void{
			for(var j:int=0;j<meshAry.length;j++){
				_weightAry = meshAry[j].weightAry;
				_meshVeterAry = meshAry[j].meshVeterAry;
				_rawUvBuffer = meshAry[j].rawUvBuffer;
				_rawPositionsBuffer = meshAry[j].rawPositionsBuffer;
				
				for(var i:int=0;i<_weightAry.length;i++){
					_weightAry[i].setResult(_jointsAry);
				}
				for(i = 0;i<_meshVeterAry.length;i++){
					_meshVeterAry[i].setResult(_weightAry);
				}
				var v3d:Vector3D;
				for(i = 0;i<_meshVeterAry.length;i++){
					v3d = _meshVeterAry[i].resultVector3D;
					_rawPositionsBuffer.push(v3d.x,v3d.y,v3d.z);
					_rawUvBuffer.push(_meshVeterAry[i].uvx,_meshVeterAry[i].uvy);
				}
				
			}
		}
		
		public function getVerter(joins:Vector.<Joint>):void{
			for(var j:int=0;j<meshAry.length;j++){
				_weightAry = meshAry[j].weightAry;
				_meshVeterAry = meshAry[j].meshVeterAry;
				_rawUvBuffer = meshAry[j].rawUvBuffer;
				_rawPositionsBuffer = meshAry[j].rawPositionsBuffer;
				
				var verAry:Vector.<Number> = new Vector.<Number>;
				meshAry[j].vertexList.push(verAry);
				for(var i:int=0;i<_weightAry.length;i++){
					_weightAry[i].setResult(joins);
				}
				for(i = 0;i<_meshVeterAry.length;i++){
					_meshVeterAry[i].setResult(_weightAry);
				}
				var v3d:Vector3D;
				for(i = 0;i<_meshVeterAry.length;i++){
					v3d = _meshVeterAry[i].resultVector3D;
					verAry.push(v3d.x,v3d.y,v3d.z);
				}
				
			}
			
			
			//return verAry;
		}
		

		public function get jointsAry():Vector.<Joint>
		{
			return _jointsAry;
		}

		public function get meshVeterAry():Vector.<MeshVertex>
		{
			return _meshVeterAry;
		}

		public function get weightAry():Vector.<Weight>
		{
			return _weightAry;
		}

		public function get rawUvBuffer():Vector.<Number>
		{
			return _rawUvBuffer;
		}

		public function get rawIndexBuffer():Vector.<uint>
		{
			return _rawIndexBuffer;
		}
		
		private var utilByte:ByteArray = new ByteArray;
		private function converFloat(value:Number):Number{
			utilByte.clear();
			utilByte.writeFloat(value);
			utilByte.position = 0;
			return utilByte.readFloat();
		}

		
	}
}